//
// Created by guoshunw on 24-6-5.
//

#ifndef HELLO_SWAPCONTEXT_LOG_H
#define HELLO_SWAPCONTEXT_LOG_H

#include <iostream>
#include <sstream>
#include <cstring>

#include <unordered_map>
#include <csignal>

enum class LogLevel {
    DEBUG = 0,
    INFO,
    WARNING,
    ERROR
};

static const std::unordered_map<LogLevel, const char *> severity_map = {
        {LogLevel::DEBUG,   "D"},
        {LogLevel::INFO,    "I"},
        {LogLevel::WARNING, "W"},
        {LogLevel::ERROR,   "E"}
};

LogLevel &getLevel();

void setLevel(LogLevel level);

class LogMessage {
    const char *file = nullptr;
    int line = 0;
    LogLevel severity = LogLevel::INFO;
    std::ostream &os;
    std::stringstream ss;

    void flush() {
        if (severity < getLevel()) return;
        os << ss.str() << std::endl;
    }

    void prefix() {
        if (severity < getLevel()) return;
        auto name = file;
        name = basename(name);
        auto tid = gettid();
        ss << severity_map.at(severity) << " " << name << ":" << line << " [" << tid << "] - ";
//        ss << name << ":" << line << ": ";
    }


public:
    LogMessage(const char *file, int line, LogLevel severity)
            : file(file), line(line), severity(severity),
              os(severity > LogLevel::INFO ? std::cerr : std::cout) {
        prefix();
    }


    std::ostream &stream() {
        return ss;
    }

    virtual ~LogMessage() { flush(); };
};

#define LOG(level) LogMessage(__FILE__, __LINE__, LogLevel::level).stream()

#define LOGD LOG(DEBUG)
#define LOGI LOG(INFO)
#define LOGW LOG(WARNING)
#define LOGE LOG(ERROR)

#endif //HELLO_SWAPCONTEXT_LOG_H
